﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Game.Custom.Interface;
using MyDebug;
using TestCstRatingConsole.BlockObjController;

namespace TestCstRatingConsole
{

    /// <summary>
    /// 物体信息管理辅助。管理：区、块、单元
    /// <para> 对于区，是存储于文件单位</para>
    /// <para> 块，是用于视图九宫格单位</para>
    /// <para> 单元，是块中的具体数据</para>
    /// </summary>
    /// <remarks>目前对于块的最小单位应该是1m，所以两个物体之间的距离至少大于1</remarks>
    class BlockInfoHelper
    {
        static BlockInfoHelper instance;

        //偏移值问题
        const int C_WorldPositionMax = 1000000000;                              //10亿，在世界实际坐标最大值
        const int C_WorldPositionMin = -1000000000;                             //-10亿，在世界的实际坐标最小值
        const int C_World2MapPosDelta = (C_WorldPositionMax-C_WorldPositionMin)/2; //实际坐标到图坐标的偏移位置，用于将负数位置的进行偏移，需确保偏移值大于0

        public int MapPositionMax {get{return C_WorldPositionMax;}}

        /// <summary>
        /// 实例。管理：区、块、单元
        /// <para> 对于区，是存储于文件单位</para>
        /// <para> 块，是用于视图九宫格单位</para>
        /// <para> 单元，是块中的具体数据</para>
        /// </summary>
        public static BlockInfoHelper g_Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new BlockInfoHelper();
                    instance.Init();
                }
                return instance;
            }
        }

        public int SceneId { get; set; }

        int BlockArea;

        ///// <summary>
        ///// 对所有砖块的存储，分为区、块、单元
        ///// 区为2维数组，块为2维数组，单元为3维数组
        ///// </summary>
        ///// <remarks> 可以使用三重Safe字典，使得区块稀疏</remarks>
        //static BrickItemInfo[,][,][,] g_allBricksCMx2D;//目前暂时用2维先行改造

        /// <summary>
        /// 对所有砖块的存储，分为区、块、单元
        /// 区为2维，块为2维，单元为3维
        /// </summary>
        /// <remarks>
        /// 使用三重Safe字典，使得区块稀疏；
        /// </remarks>
        static Dictionary<IntVector2, Dictionary<IntVector2, Dictionary<IntVector3, BrickItemInfo>>> g_dictAllBricksCMx3D;

        /// TODO：对于区被离开时，应该考虑触发删除邻近的不使用区
        _GRID_VIEW[,] g_lastBlockInView3x3;                                       //在视图9宫格中，有Brick读入时，即记录入九宫格（也就是已经在场景中显示了）


        /// <summary>
        /// 每个区块的长、宽（暂时不考虑高度）
        /// </summary>
        const int BlockSize = 256;

        #region 待裁剪字段
        static Vector3 g_playerStartPosRead;                            //读取到的玩家的起始位置
        static int g_skyBoxIndex = 0;                                       //当前使用的SkyBox序号
        /// <summary>
        /// 目前正在绘制的地图名称
        /// </summary>
        string m_currMapNamePainting = null;

        //TODO:砖块的大小，如果改动了BlockManager的Setting预设值，这里也需要相应更改砖块大小
        const int C_BRICK_WIDTH = 20;                                   //X上的宽度
        const int C_BRICK_HEIGHT = 20;                                  //Y上的高度
        const int C_BRICK_THINCKNESS = 20;                          //Z上

        //最小单元大小：（用于9显示格）
        //16=2^4:移位4
        /// <summary>
        /// 转换到对应的单元/块/区所需要的移位数目
        /// </summary>
        const int C_2bit_TO_UNIT_BLOCK_AREA = 5;
        /// <summary>
        /// 每个块的边长大小
        /// </summary>
        /// <remarks>
        /// 位移对应的位置，目前为2^5=32，对应的，总面积为其平方，体积为立方
        /// </remarks>
        const int C_SIZE_OF_UBA = 1 << C_2bit_TO_UNIT_BLOCK_AREA;
        #endregion


        void Init()
        {
            //初始化存储空间：
            //g_allBricksCMx2D = new BrickItemInfo[C_SIZE_OF_UBA, C_SIZE_OF_UBA][,][,];
            g_dictAllBricksCMx3D = new Dictionary<IntVector2, Dictionary<IntVector2, Dictionary<IntVector3, BrickItemInfo>>>();
            g_lastBlockInView3x3 = new _GRID_VIEW[3, 3];
            ClearLastBlockHistroy();
            //Debug.Log("Generate area:" + g_allBricksCMx2D.Length);
        }

        #region public part
        /// <summary>
        /// 将砖块信息存入内存。如果之前已经存在，会直接覆盖原有信息
        /// </summary>
        public void PushBrickData(BrickItemInfo brick)
        {
            IntVector2 blockID, areaID;
            IntVector3 unitID;

            //获得所属单元号
            IntVector3 gridPos = GetUnitBlockAreaIDFromBrick(brick.position, out unitID, out blockID, out areaID);

            //因为目前是用tag来获取物体的，所以物体可能无法反向关联属于自己的Info，所以设置了area、Block、Unit ID也不会有啥用
            //brick.areaId = areaID;
            //brick.blockId = blockID;
            //brick.unitId = unitID;

            //Debug.Log("Created grid"+gridPos+"("+brick.position+") belong to-> area " + areaID+" block "+blockID+" unit "+unitID);
            //该区中的块还未申请空间的情况下
            if (!HasAreaData(areaID))
            {
                //生成该区中的块：
                GenerateBlockMemForArea(areaID);
            }

            //该块中的单元还未申请空间的情况下：
            if (!HasBlockData(areaID, blockID))
            {
                //生成单元，每个单元含size*size个单位。
                GenerateUnitMemForBlock(areaID, blockID);
            }

            //标记为有数据
            brick.hasData = true;

            //将Brick数据引入该位置
            //g_allBricksCMx2D[areaID.x, areaID.z][blockID.x, blockID.z][unitID.x, unitID.z] = brick;
            g_dictAllBricksCMx3D[areaID][blockID][unitID] = brick;
        }

        /// <summary>
        /// 删除某个位置的信息（需要确保有该物体、该位置的情况下），并返回是否删除成功
        /// </summary>
        /// <param name="brickPos"></param>
        public bool RemoveBrickDataAtPos(Vector3 brickPos)
        {
            IntVector3 unitID;
            IntVector2 blockID, areaID;

            //删除是基于进入了该区、块的情况下进行的，所以不再判断是否存在该区块
            //--获得所属单元号
            GetUnitBlockAreaIDFromBrick(brickPos, out unitID, out blockID, out areaID);

            //标记为无数据
            //g_allBricksCMx2D[areaID.x, areaID.z][blockID.x, blockID.z][unitID.x, unitID.z].hasData = false;
            //此处可能会报错，因为对于移动的物体，移动到某位置，再被移除时，移除的位置信息会不对；
            return g_dictAllBricksCMx3D[areaID][blockID].Remove(unitID);
        }

        /// <summary>
        /// 改变某一个位置的砖块自定义信息
        /// </summary>
        public void SetBrickCustomData(Vector3 brickPos, CustomData[] customDatas)
        {
            IntVector3 unitID;
            IntVector2 blockID, areaID;
            //获得所属单元号
            IntVector3 gridPos = GetUnitBlockAreaIDFromBrick(brickPos, out unitID, out blockID, out areaID);

            //Debug.Log("POS:" + gridPos);
            //g_allBricksCMx2D[areaID.x, areaID.z][blockID.x, blockID.z][unitID.x, unitID.z].customDatas = customDatas;
            g_dictAllBricksCMx3D[areaID][blockID][unitID].customDatas = customDatas;
        }

        public void ClearAllBricksData()
        {
            foreach (var area in g_dictAllBricksCMx3D.Values)
            {
                foreach (var block in area.Values)
                {
                    //这里不是往下遍历，而是直接Clear该字典，所以并不会引起Area的迭代器报错：
                    block.Clear();
                }
            }

        }

        private IntVector2[] listDirectionX9 = null;
        /// <summary>
        /// 获取视图中所有的Bricks数据，自动识别原有读取过的Block，如果无视图变化，则返回NULL
        /// </summary>
        public List<BrickItemInfo> GetBricksDataInView(Vector3 position)
        {
            IntVector3 unitID;
            IntVector2 blockID, areaID;
            IntVector3 gridPos = GetUnitBlockAreaIDFromBrick(position, out unitID, out blockID, out areaID);
            //Debug.Log("curr view is block" + blockID);
            //发现这个grid并没有超出上次停留的Block
            if (!IsBlockViewHasMoved(areaID, blockID, 1, 1))//（1,1）即为九宫格中心位置
            {
                //Debug.LogWarning("reject querry.view didn't change.");
                return null;
            }

            //最大可能有256个
            List<BrickItemInfo> resultList = new List<BrickItemInfo>(C_SIZE_OF_UBA * C_SIZE_OF_UBA);

            if(listDirectionX9==null)
            {
                //探测方向：从0，左上，上，右上...这样的顺序逐渐遍历
                listDirectionX9 = new IntVector2[]{
                    new IntVector2(0,0),
                    new IntVector2(-1,1),
                    new IntVector2(0,1),
                    new IntVector2(1,1),
                    new IntVector2(-1,0),
                    new IntVector2(1,0),
                    new IntVector2(-1,-1),
                    new IntVector2(0,-1),
                    new IntVector2(1,-1),
                };
            }

            //9个方向，探测4个Area 尝试拿到9个Block中的结果：
            IntVector2 blockX9 = new IntVector2();                              //9个中指定的一个Block
            IntVector2 blockDeltaX9 = new IntVector2();                     //block在九宫格视图中的偏移值
            for (var i = 0; i < listDirectionX9.Length;i++ )
            {
                blockDeltaX9 = listDirectionX9[i];
                blockX9 = blockID + listDirectionX9[i];

                //拿到这个Block中的所有Bricks，送入List
                GetBricksDataInBlock(areaID, blockX9, blockDeltaX9, resultList);
            }

            ////原来遍历9方向的代码：
            //for (int i = -1; i < 2; i++)
            //{
            //    blockDeltaX9.x = i;
            //    for (int j = -1; j < 2; j++)
            //    {
            //        blockDeltaX9.z = j;
            //        blockX9.x = blockID.x + i;
            //        blockX9.z = blockID.z + j;
            //        //拿到这个Block中的所有Bricks，送入List
            //        //Debug.Log("i " + i + "  j " + j);
            //        GetBricksDataInBlock(areaID, blockX9, blockDeltaX9, resultList);
            //    }
            //}

            //Debug.Log("Read " + resultList.Count + " at this time.");
            return resultList;
        }


        /// <summary>
        /// 获取超出视图的所有区块中的数据予以删除
        /// </summary>
        /// <param name="viewPos">当前镜头位置</param>
        public List<BrickItemInfo> UnloadAreaData(Vector3 viewPos)
        {
            List<BrickItemInfo> result = new List<BrickItemInfo>();

            //此处是以区块做距离的判断，而不以九宫格为标准。当内存中的区块与当前距离相去甚远，则需要尝试卸载不需要的区块数据
            IntVector2 viewBlockID, viewAreaID;
            IntVector3 viewUnitID;
            GetUnitBlockAreaIDFromBrick(viewPos, out viewUnitID, out viewBlockID, out viewAreaID);

            IntVector2 currAreaID;
            List<IntVector2> areaIdToClean = new List<IntVector2>();
            //遍历内存中已有的区：
            foreach(var areaData in g_dictAllBricksCMx3D)
            {
                currAreaID = areaData.Key;
                if(currAreaID.LinerDistanceTo(viewAreaID)>=3//目前假设横扫距离在3个区外（含）则需要清理：
                    && areaData.Value !=null && areaData.Value.Count > 0
                    )
                {
                    //将之存入文件：
                    SaveAreaBrikcData( GetCurrMapDataPath(), currAreaID);

                    //该区内的都添加到结果列表中
                    foreach(var blockData in areaData.Value)
                    {
                        foreach(var unitData in blockData.Value)
                        {
                            result.Add(unitData.Value);
                        }
                    }

                    areaIdToClean.Add(currAreaID);
                }
            }
            //删除区数据：
            foreach(var cleanArea in areaIdToClean)
            {
                g_dictAllBricksCMx3D.Remove(cleanArea);
            }


            return result;
        }

        //TODO: 还原此块代码
        ///// <summary>
        ///// 获取超出视图的所有GameObject
        ///// </summary>
        //public List<GameObject> FindGObjOutOfView(Vector3 viewPos, List<Transform> listTransToCheck)
        //{
        //    List<GameObject> listObjToDestroy = new List<GameObject>(C_SIZE_OF_UBA);
        //    IntVector2 viewUnitID, viewBlockID, viewAreaID;
        //    IntVector2 objUnitID, objBlockID, objAreaID;

        //    //获得Camera的Block、Area
        //    GetUnitBlockUnitIDFromBrick(viewPos, out viewUnitID, out viewBlockID, out viewAreaID);

        //    //计算出中心视图在网格中的x、y值：类似于数组下标计算，area的权值为16，block权值为1，方便跟其他物体的区域位置比对

        //    //Debug.LogWarning("view pos:" + viewAreaID + "," + viewBlockID);

        //    IntVector2 posDelta;

        //    for (int i = 0; i < listTransToCheck.Count; i++)
        //    {
        //        //如果这个物体已经是被自己删除了，则不再计入
        //        if (listTransToCheck[i] == null)
        //        {
        //            //原来的表就应该剔除数据了。
        //            listTransToCheck.RemoveAt(i);

        //            //List下标变化，回退。
        //            i--;

        //            continue;
        //        }

        //        //获得这个游戏物体的Block、Area
        //        GetUnitBlockUnitIDFromBrick(listTransToCheck[i].position, out objUnitID, out objBlockID, out objAreaID);

        //        //与视图中心比对，如果超过，则证明已经不在区域范围内：
        //        //--求位置差值
        //        posDelta = DistanceOfUnit(viewAreaID, viewBlockID, objAreaID, objBlockID);

        //        //--判断是否在范围内: 9宫格中心附近的则序号差值不超过1
        //        if (posDelta.x > 1 || posDelta.y > 1)
        //        {
        //            //判断是否是代理物体，代理物体拥有不入Destroy列表的选择
        //            if (listTransToCheck[i].GetComponent<CM_DelegateObj>())
        //            {
        //                //Debug.Log("ignore to add to list and announce it...");
        //                listTransToCheck[i].GetComponent<CM_DelegateObj>().AnnounceOutOfView();
        //            }
        //            else
        //            {
        //                //将这个游戏物体入表吧！我们要给他送葬了。
        //                listObjToDestroy.Add(listTransToCheck[i].gameObject);

        //                //原来的表就应该剔除数据了。
        //                listTransToCheck.RemoveAt(i);

        //                //List下标变化，回退。
        //                i--;
        //            }
        //        }

        //    }

        //    return listObjToDestroy;
        //}

        //销毁前操作
        public static void DestoryMe()
        {
            //if(m_instance != null)
            //   m_instance.SaveAllBricksData();
            //g_allBricksCMx2D = null;
            instance.ClearAllBricksData();

            instance = null;
            Debug.Log("Destroyed.");
        }


        public void CreateNewMap()
        {
            //Clear all area's data of current map:
            ClearAllBricksData();

            //Set name to null:
            m_currMapNamePainting = null;
        }

        public void OpenMap(string mapName)
        {
            //设置地图名，动态读取
            m_currMapNamePainting = mapName;

            //清除之前的数据
            ClearAllBricksData();
            ClearLastBlockHistroy();

            //读取地图的其他设定
            ReadMapSetting();
        }

        public int GetMapSkyBoxID()
        {
            return g_skyBoxIndex;
        }

        /// <summary>
        /// 返回起点所在位置
        /// </summary>
        public Vector3 GetMapStartPosition()
        {
            return g_playerStartPosRead;
        }

        ///// <summary>
        ///// 返回终点所在位置
        ///// </summary>
        //public Vector3 GetMapEndPosition()
        //{
        //    return g_WinCheckerEndPosRead;
        //}

        //默认为不删除存在地图；如果是覆盖时，则先删除原有文件
        public void SaveMap(string saveAs, bool deleteExist = false)
        {
            //Set mapName to be saved:
            SaveAllBricksData(saveAs, deleteExist);
        }

        public void DeleteCurrMap(string mapName = null)
        {
            if (mapName == null)
            {
                mapName = m_currMapNamePainting;
            }

            //Both is null:
            if (mapName == null)
                return;

            m_currMapNamePainting = mapName;

            //Now make sure the directory is exist:
            if (Directory.Exists(GetCurrMapDataPath()))
            {
                Debug.Log("path to delete:" + GetCurrMapDataPath());
                Directory.Delete(GetCurrMapDataPath(), true);
                m_currMapNamePainting = null;
                ClearAllBricksData();
            }

        }


        /// <summary>
        /// 获得所有的地图文件名
        /// </summary>
        /// <returns></returns>
        public string[] GetAllMapsNames()
        {
            //探测存储目录下的所有地图文件夹，即为地图文件名
            DirectoryInfo[] dirInfo = new DirectoryInfo(GetMapSavePath()).GetDirectories();
            int mapsFileCount = dirInfo.Length;
            string[] mapFilesName = new string[mapsFileCount];
            for (int i = 0; i < mapsFileCount; i++)
            {
                //--Fetch file's name
                mapFilesName[i] = dirInfo[i].Name;
            }

            return mapFilesName;
        }


        public bool IsMapFileExist(string saveNameInputed)
        {

            return Directory.Exists(
                GetMapSavePath() + saveNameInputed
                );
        }

        public bool testTryReadArea(int x, int y)
        {
            return TryReadAreaFromFile(x, y);
        }

        /// <summary>
        /// 获取当前的地图名
        /// </summary>
        public string GetCurrentMapName()
        {
            return m_currMapNamePainting;
        }

        public void SetBGSkyBoxData(int index)
        {
            g_skyBoxIndex = index;
        }
        #endregion


        public void Test()
        {
            string path = @"F:\PersonalProj\Test\";
        }

        #region private part
        //---------------------------------------------------------------------------------------------------------------------
        //                                                              私有函数
        //---------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 判断当前区域与上次所在区域相比，是否移动了
        /// </summary>
        private bool IsBlockViewHasMoved(IntVector2 areaID, IntVector2 blockID, int g9x, int g9y)
        {
            return !g_lastBlockInView3x3[g9x, g9y].IsEquals(areaID, blockID);
        }

        /// <summary>
        /// 清除保存的当前区域是否移动了的历史记录
        /// </summary>
        private void ClearLastBlockHistroy()
        {
            for (int i = 0; i < 3; i++)
                for (int j = 0; j < 3; j++)
                    g_lastBlockInView3x3[i, j].SetNull();
        }

        /// <summary>
        /// 获得指定区块中的所有单位，并放入List中.如果上次已经读取了此单元内容，则不添加入结果列表中
        /// </summary>
        /// <param name="refToList">用于存放结果的列表</param>
        /// <param name="areaID"></param>
        /// <param name="blockID"></param>
        /// <param name="blockDeltaX9">此BLOCK于视图9宫格的位置 (x偏移值、y偏移值）</param>        
        private void GetBricksDataInBlock(IntVector2 areaID, IntVector2 blockID, IntVector2 blockDeltaX9, List<BrickItemInfo> refToList)
        {
            //此BLOCK于视图9宫格的位置 (x偏移值)
            int g9x = blockDeltaX9.x, g9y = blockDeltaX9.z;

            //TODO:有问题：对于地图大时，会导致读入的数据越来越多，而没有清理超出距离的内容
            //TODO 问题2：对于负数支持不友好！负数区块会被认为是错误数据。或者可以这么处理：认定正负10亿范围，直接对-10亿增加10亿的偏移距离
            #region 判断这个BLock是否已经被读取过，并记录下有可能错误的Area、Block（但是是唯一标示）
            //看看这个Block上次是不是读取过了？
            //--纠正想要查询的坐标（原来是-1,0,1的)
            g9x += 1;
            g9y += 1;

            //--恰好是最左上的格子想要检测，则先进行视图中的九宫格移位判断（这样后续的才有机会对上正确的位置）
            if (g9x == 0 && g9y == 0)
            {
                //--判断是否为空:为空则跳过移位
                if (!g_lastBlockInView3x3[0, 0].IsNull())
                {
                    //Debug.LogWarning("Find corner");
                    //新做法：既然已经知道了新的block目标，又知道确切的左上角/中心位置，干嘛不直接获取新的点与旧的点之间的向量差？
                    //获得新的距离差之后，直接搬运为新的即可。。。
                    //--获得新旧距离差
                    IntVector2 blockPosDelta = DeltaOfUnit(areaID, blockID, g_lastBlockInView3x3[0, 0].areaID, g_lastBlockInView3x3[0, 0].blockID);

                    //Debug.LogWarning("pos deta:" + blockPosDelta);
                    #region 九宫格移位操作
                    //--由于是连续移动的，所以跨格子的现象并不会那么频繁出现。
                    //if (blockPosDelta.x < 3 && blockPosDelta.y<3 && blockPosDelta.x>-3 && blockPosDelta.y>-3)
                    //{
                    _GRID_VIEW[,] cpySrc = new _GRID_VIEW[3, 3];

                    //--做好一个备份工作
                    for (int i = 0; i < 3; i++)
                        for (int j = 0; j < 3; j++)
                            cpySrc[i, j] = g_lastBlockInView3x3[i, j];
                    //--移位
                    //--
                    int srcX = 0, srcY = 0;
                    //---搬运开始了：从中心点的左上角开始
                    for (int i = 0; //start为目的地，from为搬运点，如果超过搬运点，则对目的地填NULL
                        i < 3;
                        i++)
                    {
                        for (int j = 0; j < 3; j++)
                        {
                            //--得到源位置：
                            srcX = i + blockPosDelta.x;
                            srcY = j + blockPosDelta.z;
                            if (srcX >= 3 || srcX < 0
                                || srcY >= 3 || srcY < 0
                                )//--越界，则意味着搬运到头了
                                g_lastBlockInView3x3[i, j].SetNull();
                            else
                                g_lastBlockInView3x3[i, j] = cpySrc[srcX, srcY];

                        }
                    }


                    ////Debug.Log("after move:");
                    //for (int j = 2; j >= 0; j--)
                    //{
                    //    string line = "";
                    //    for (int i = 0; i < 3; i++)
                    //    {
                    //        line += g_lastBlockInView3x3[i, j].blockID;
                    //    }
                    //    //Debug.LogWarning("recorder:" + line);
                    //}
                    ////}
                    #endregion
                }
            }


            #endregion

            //现在才开始纠正Block和真正读取Block
            if (!CorrectBlockID(ref areaID.x, ref blockID.x)
            || !CorrectBlockID(ref areaID.z, ref blockID.z)
                )
            {
                //这个Block是错误的Block，无数据，返回，无操作
                return;
            }

            //仍旧越界，代表镜头还是超出范围了：
            if ((areaID.x < 0 || areaID.x > C_SIZE_OF_UBA)
                || (areaID.z < 0 || areaID.z > C_SIZE_OF_UBA))
                return;


            if (blockID.x < 0)
            {
                Debug.LogWarning("block:" + blockID + " is occured.");
            }

            //--如果是上次已经读过的Block，则无需再读
            if (g_lastBlockInView3x3[g9x, g9y].IsEquals(areaID               //上次读过的区（已经进入视图啦）
                                                                            , blockID))               //上次读过的块（已经进入视图啦）
            {
                //Debug.LogWarning(areaID+" "+blockID + "already readed");
                return;
            }

            //要开始读某个Block之前，把这个Block信息记录下来
            g_lastBlockInView3x3[g9x, g9y].areaID = areaID;
            g_lastBlockInView3x3[g9x, g9y].blockID = blockID;
            //Debug.LogWarning("read" + areaID + " " + blockID);

            //好的，这个区这个块我要了！
            if (!HasAreaData(areaID))
            {
                //内存中还没有该区块的信息时，尝试读取文件，建立对应的区块信息
                //Debug.Log("read for not read yet. area:"+areaID+" block:"+blockID);
                if (!TryReadAreaFromFile(areaID.x, areaID.z))
                {
                    //这个区也不存在任何数据文件
                    return;
                }
            }

            if (!HasBlockData(areaID, blockID))
            {
                //Debug.Log("area" + areaID + " block" + blockID + " 都不存在，整哈呢？");
                return;
            }

            //喜闻乐见的遍历来了:把这个Block内的所有Units读取并添加入List，抓起来送入视图吧！哈哈哈哈哈
            foreach (var brickInfo in g_dictAllBricksCMx3D[areaID][blockID].Values)
            {
                refToList.Add(brickInfo);
            }

            //for (int i = 0; i < C_SIZE_OF_UBA; i++)
            //{
            //    for (int j = 0; j < C_SIZE_OF_UBA; j++)
            //    {
            //        //存在数据，则添加入list
            //        if (g_allBricksCMx2D[areaID.x, areaID.z][blockID.x, blockID.z][i, j].hasData)
            //        {
            //            toList.Add(g_allBricksCMx2D[areaID.x, areaID.z][blockID.x, blockID.z][i, j]);
            //        }
            //    }
            //}

        }

        /// <summary>
        /// 纠正BlockID信息：处理块溢出时的移位，如果会造成区溢出（即到了地图边界），则返回false
        /// </summary>
        private bool CorrectBlockID(ref int areaP, ref int blockP)
        {
            if (blockP < 0)
            {

                //shi了，这个家伙越界了,区域也要随之少一个区：
                areaP -= 1;

                //结果这个渣渣也越界了……好吧，那么就到头了，世界坐标。
                if (areaP < 0)
                {
                    return false;
                }

                //如果没越界，那么就在这个区中，但是块变了：
                blockP = C_SIZE_OF_UBA - 1;

                //Debug.Log("Block边界<0溢出,纠正到新区" + areaP + "新块"+blockP);
            }

            else if (blockP >= C_SIZE_OF_UBA)
            {
                //越界了，BLOCK越界了！
                areaP += 1;
                if (areaP >= C_SIZE_OF_UBA)//连区都越界了，还能说什么呢？？？
                {
                    return false;
                }

                //纠正区位信息：
                blockP = 0;
                Debug.Log("Block边界>=16溢出，纠正到新区：" + areaP + " new block:" + blockP);
            }

            //纠正成功
            return true;
        }

        /// <summary>
        /// 探查该区是否有数据
        /// </summary>
        private bool HasAreaData(IntVector2 areaID)
        {
            return g_dictAllBricksCMx3D.ContainsKey(areaID);
        }

        /// <summary>
        /// 探查该区块是否有数据
        /// </summary>
        private bool HasBlockData(IntVector2 areaId, IntVector2 block)
        {
            return g_dictAllBricksCMx3D.ContainsKey(areaId) && g_dictAllBricksCMx3D[areaId].ContainsKey(block);
        }


        /// <summary>
        /// 为块生成单元空间
        /// </summary>>
        private void GenerateUnitMemForBlock(IntVector2 areaID, IntVector2 blockID)
        {
            //g_allBricksCMx2D[areaID.x, areaID.z][blockID.x, blockID.z] =
            //        new BrickItemInfo[C_SIZE_OF_UBA, C_SIZE_OF_UBA];

            g_dictAllBricksCMx3D[areaID][blockID] = new Dictionary<IntVector3, BrickItemInfo>();
        }

        /// <summary>
        /// 生成区中的块空间
        /// </summary>
        private void GenerateBlockMemForArea(IntVector2 areaId)
        {
            //g_allBricksCMx2D[x, y] =
            //        new BrickItemInfo[C_SIZE_OF_UBA, C_SIZE_OF_UBA]          //size * size
            //        [,];

            //用Add而不用[]，测试时确保不会出现重复调用Generate的问题：
            g_dictAllBricksCMx3D.Add(areaId, new Dictionary<IntVector2, Dictionary<IntVector3, BrickItemInfo>>());
        }

        private IntVector2 GetUnitBlockUnitIDFromBrick(Vector3 brickPos, out IntVector2 unitID, out IntVector2 blockID, out IntVector2 areaID)
        {
            throw new NotImplementedException("NOT for 2d area");
        }


        /// <summary>
        /// 获得砖块所属的单元、块、区域
        /// </summary>
        /// <param name="brickPos">砖块的世界坐标位置</param>
        /// <param name="unitID">返回的单元值</param>
        /// <param name="blockID">返回的块值</param>
        /// <param name="areaID">返回的区值</param>
        /// <returns>返回砖块在网格中的坐标位置。</returns>
        private IntVector3 GetUnitBlockAreaIDFromBrick(Vector3 brickPos, out IntVector3 unitID, out IntVector2 blockID, out IntVector2 areaID)
        {
            //避免负数，直接加上偏移值：
            int posX = (int)brickPos.x + C_World2MapPosDelta,
                posY = (int)brickPos.y + C_World2MapPosDelta,
                posZ = (int)brickPos.z + C_World2MapPosDelta;


            IntVector3 gridPos = new IntVector3(posX, posY, posZ);
            ////先转换砖块的位置-》网格位置
            //ConvertWorldPositionToGridPos(ref gridPos);

            unitID = new IntVector3();              //创建赋值
            blockID = new IntVector2();
            areaID = new IntVector2();
            int modLeft = 0;                                //余数
            //获得网格位置在单元中的所属
            #region 举例注释
            //例如：
            //482
            //->482/256=第 1 区 --%226    位移8
            //->226/16 =第 14块 --%2        位移4
            //->                第2个单元
            //此处16为块最大边长
            //区为对应边长的平方
            #endregion
            //--X上
            areaID.x = gridPos.x >> (C_2bit_TO_UNIT_BLOCK_AREA * 2);             //右移两次
            modLeft = gridPos.x % (1 << (C_2bit_TO_UNIT_BLOCK_AREA * 2));

            blockID.x = modLeft >> (C_2bit_TO_UNIT_BLOCK_AREA);                 //右移一次
            modLeft = modLeft % (1 << C_2bit_TO_UNIT_BLOCK_AREA);

            unitID.x = modLeft;

            //--Z上的：
            areaID.z = gridPos.z >> (C_2bit_TO_UNIT_BLOCK_AREA * 2);             //右移两次
            modLeft = gridPos.z % (1 << (C_2bit_TO_UNIT_BLOCK_AREA * 2));

            blockID.z = modLeft >> (C_2bit_TO_UNIT_BLOCK_AREA);                 //右移一次
            modLeft = modLeft % (1 << C_2bit_TO_UNIT_BLOCK_AREA);

            unitID.z = modLeft;

            //--y的只有到unit才有：
            unitID.y = gridPos.y % (1 << (C_2bit_TO_UNIT_BLOCK_AREA * 3));    //直接右移3次

            //封印Z
            //gridPos.z = gridPos.z >>
            return gridPos;
        }


        /// <summary>
        /// 将坐标转换为网格位置
        /// </summary>
        private void ConvertWorldPositionToGridPos(ref IntVector2 iv3)
        {
            iv3.x = iv3.x / C_BRICK_WIDTH;
            iv3.z = iv3.z / C_BRICK_HEIGHT;
            //z值封印
            //iv3.z = iv3.z / C_BRICK_THINCKNESS;
        }


        //从给定的Area、Block中计算出对应的Pos
        int GetUnitPosFrom(int areaID, int blockID)
        {
            return areaID * C_SIZE_OF_UBA + blockID;
        }

        /// <summary>
        /// 总是返回一个正值
        /// </summary>
        IntVector2 DistanceOfUnit(IntVector2 area_1, IntVector2 block_1, IntVector2 area_2, IntVector2 block_2)
        {
            return DeltaOfUnit(area_1, block_1, area_2, block_2, true);

        }

        /// <summary>
        /// 返回两个单元之间的差值：用A1-A2
        /// </summary>
        IntVector2 DeltaOfUnit(IntVector2 area_1, IntVector2 block_1, IntVector2 area_2, IntVector2 block_2, bool abs = false)
        {
            int area1PosX = GetUnitPosFrom(area_1.x, block_1.x);
            int area1PosY = GetUnitPosFrom(area_1.z, block_1.z);

            int area2PosX = GetUnitPosFrom(area_2.x, block_2.x);
            int area2PosY = GetUnitPosFrom(area_2.z, block_2.z);

            IntVector2 result;
            if (abs)
            {
                result.x = Mathf.Abs(area1PosX - area2PosX);
                result.z = Mathf.Abs(area1PosY - area2PosY);
            }
            else
            {
                result.x = (area1PosX - area2PosX);
                result.z = (area1PosY - area2PosY);
            }
            return result;
        }

        /// <summary>
        /// 物体数据存储
        /// </summary>
        /// <param name="mapName">地图名（也就是文件夹名字）</param>
        /// <param name="deleteExist">是否删除之前的地图数据</param>
        void SaveAllBricksData(string saveAs, bool deleteExist = false)
        {
            m_currMapNamePainting = saveAs;

            //获得当前地图文件的存储目录（不存在时自动创建）
            string dirPath = GetCurrMapDataPath();
            if (deleteExist)
            {
                //需要覆盖的，则删除该目录
                Directory.Delete(dirPath, true);

                //再重新创建一次该目录：
                dirPath = GetCurrMapDataPath();
            }

            string filePath;
            IntVector2 areaPos = new IntVector2(0, 0);
            IntVector2 blockPos = new IntVector2(0, 0);
            IntVector3 unitPos = new IntVector3(0, 0);
            //地图文件存储：
            //--区判断：如果区不存在则跳过
            for (areaPos.x = 0; areaPos.x < C_SIZE_OF_UBA; areaPos.x++)
            {
                for (areaPos.z = 0; areaPos.z < C_SIZE_OF_UBA; areaPos.z++)
                {
                    if (!HasAreaData(areaPos))
                    {
                        continue;
                    }
                    Debug.Log("area:" + areaPos.x + ":" + areaPos.z + " has data:");
                    #region 区内容写入：
                    SaveAreaBrikcData(dirPath, areaPos);
                    

                    #endregion
                }
            }
            
            SaveMapSetting();

            //TODO:后期可以选择压缩文件达到更小体积
            Debug.Log("path:" + dirPath);
        }

        private void SaveAreaBrikcData(string dirPath, IntVector2 areaPos)
        {
            //----该区不空，则进入写数据：
            string filePath = dirPath + GetMapBlockNameAt(areaPos.x, areaPos.z);

            //文件流
            StreamWriter fileStream = new StreamWriter(filePath, false);
            IntVector2 blockPos = new IntVector2(), unitPos = new IntVector2();
            
            //创建内容：
            //遍历Block
            for (blockPos.x = 0; blockPos.x < C_SIZE_OF_UBA; blockPos.x++)
            {
                for (blockPos.z = 0; blockPos.z < C_SIZE_OF_UBA; blockPos.z++)
                {
                    if (!HasBlockData(areaPos, blockPos))
                    {
                        //太好了,该块为空， 下一个
                        continue;
                    }

                    System.Text.StringBuilder blockContents = new System.Text.StringBuilder();
                    
                    //否则还是得遍历Unit啊……囧
                    //保存块里的所有数据，后期可以直接记录单元序号，偏移信息：
                    foreach(var brickInf in g_dictAllBricksCMx3D[areaPos][blockPos].Values)
                    {
                        if(brickInf !=null && brickInf.hasData )
                        {
                            blockContents.Append(brickInf.ToSavedString());
                        }
                    }

                    ////遍历Unit
                    //for (unitPos.x = 0; unitPos.x < C_SIZE_OF_UBA; unitPos.x++)
                    //{
                    //    for (unitPos.z = 0; unitPos.z < C_SIZE_OF_UBA; unitPos.z++)
                    //    {
                    //        //brickInf = g_allBricksCMx2D[areaPos.x, areaPos.z][blockPos.x, blockPos.z][unitPos.x, unitPos.z];
                    //        brickInf = g_dictAllBricksCMx3D[areaPos][blockPos][unitPos];
                    //        if (brickInf == null || brickInf.hasData == false)
                    //        {
                    //            //这个单元也是废的，下一个！
                    //            continue;
                    //        }
                    //        //保存到block内容中（此处，后期其实可以精简位置，因为知道了区（文件名）、块（未记录，但可在行首记录），则可直接记录单元的序号和偏移尾数即可）
                    //        blockContents.Append(brickInf.ToSavedString());
                    //    }
                    //}

                    //遍历Block中的Unit完成，写入文件:一行为一个Block（含最多16*16个=256个砖块）
                    fileStream.Write(blockContents + "\n");

                }
            }

            fileStream.Flush();
            fileStream.Close();
            fileStream.Dispose();
        }

        /// <summary>
        /// 保存Map的设置，并保存一些自定义的内容，以扩展内容
        /// </summary>
        /// <param name="customString"></param>
        private void SaveMapSetting(string customString=null)
        {

            //地图的特殊设置的写入：
            StreamWriter sw = new StreamWriter(GetCurrMapDataPath() + GetMapSettingName(), false);
            //--写入SkyBox
            sw.Write(g_skyBoxIndex + "\n");

            //--玩家位置：
            //----获取放置的位置
#if UNITY
            Vector3 startPos = CM_DelegateObj.FindPositionOfDelegate(Game.Custom.CustomObjType.Player);
#else
            Vector3 startPos = new Vector3();
#endif

            string posStr = startPos.x.ToString() + ',' + startPos.y;
            //----写入玩家位置
            sw.Write(posStr + "\n");

            //--终点位置：
            //----获取位置
            //Debug.LogError("NO End pos found,以下被注释");
            //Vector3 endPos = CM_DelegateObj.FindPositionOfDelegate(CM_DelegateObj.DELEGATE_TYPE.WinChecker);
            //posStr = endPos.x.ToString() + ',' + endPos.y;
            //----写入终点的位置
            //sw.Write(posStr+"\n");

            //自定义数据：
            if (!string.IsNullOrEmpty(customString))
            {
                sw.Write(customString);
            }

            //--写入完成，Flush
            sw.Flush();
            sw.Close();
            sw.Dispose();

        }

        /// <summary>
        /// 读取Map的设置，并返回一些自定义的内容，以扩展读取内容
        /// </summary>
        /// <returns></returns>
        private string ReadMapSetting()
        {
            StreamReader sr = new StreamReader(GetCurrMapDataPath() + GetMapSettingName());

            //读入SkyBox 设置
            string line = sr.ReadLine();
            if (line.Length > 0)
            {
                int skyMapId = 0;
                int.TryParse(line, out skyMapId);
                g_skyBoxIndex = skyMapId;
            }

            line = sr.ReadLine();
            if (line.Length > 0)
            {
                //解析Pos
                string[] pos = line.Split(',');
                if (pos.Length >= 2)
                {
                    Vector3 v3Pos = Vector3.zero;
                    float.TryParse(pos[0], out v3Pos.x);
                    float.TryParse(pos[1], out v3Pos.y);
                    //送入起点
                    g_playerStartPosRead = v3Pos;

                }
                else
                {
                    Debug.LogError("Wrong pos.");
                }
            }

            string customString = sr.ReadToEnd();

            sr.Close();

            return customString;
        }


        /// <summary>
        /// 实时的数据读取.将所有文件读入内存中。不存在数据则返回false
        /// </summary>
        bool RuntimeReadData(string mapName)
        {
            //目录获取
            string dataPath = GetCurrMapDataPath();

            //获取目录下的所有文件
            DirectoryInfo direInfo = new DirectoryInfo(dataPath);
            FileInfo[] dataFiles = direInfo.GetFiles();

            //无文件，则返回
            if (dataFiles.Length <= 0)
            {
                Debug.Log("No file found.");
                return false;
            }

            //遍历所有的文件，入区
            for (int i = 0; i < dataFiles.Length; i++)
            {
                //去掉尾：
                string fileName = dataFiles[i].Name;

                if (!fileName.Contains(".map"))
                {
                    //非目标文件
                    Debug.Log(fileName + " is not a legal file. Skip.");
                    continue;
                }

                //抠掉".map"4个长度，以解析文件名
                fileName = fileName.Remove(fileName.Length - 4);

                //解析文件名：
                string[] areaStrGot = fileName.Split('-');

                if (areaStrGot.Length < 2)
                {
                    Debug.Log(areaStrGot.Length + " does not satisfy condition...");
                    continue;
                }

                int areaX, areaY;
                if (!int.TryParse(areaStrGot[0], out areaX) ||
                    !int.TryParse(areaStrGot[1], out areaY))            //没成功转出数字
                {
                    Debug.Log("Fail to parse int out from string->" + areaStrGot[0] + ":" + areaStrGot[1]);
                    continue;
                }

                Debug.Log("sucess to get area id:" + areaX + ":" + areaY);

                //转出区号之后，开始读取此文件：
                if (!TryReadAreaFromFile(areaX, areaY, true))
                {
                    Debug.Log("Fail to read area" + areaX + ":" + areaY + " file. Maybe it is broken.");
                    //Skip to next.
                    continue;
                }
            }

            return true;
        }

        /// <summary>
        /// 尝试读取(x,y)区的文件，读入内存中。如果读入文件失败则返回false
        /// </summary>
        private bool TryReadAreaFromFile(int areaX, int areaY, bool isSuredFileExist = false)
        {
            if (m_currMapNamePainting == null)
                return false;

            //生成读取文件完整目录
            string fileFullPath = GetCurrMapDataPath() + GetMapBlockNameAt(areaX, areaY);

            //如果没有确定文件是存在的，那么即探测文件是否存在
            if (!isSuredFileExist)
            {
                if (!new FileInfo(fileFullPath).Exists)
                {
                    return false;
                }
            }

            Debug.Log("Read :" + fileFullPath);

            StreamReader streamReader = new StreamReader(fileFullPath);
            string lineData;                                //读取到的行（块）
            string[] unitsStr;                              //行中可拆分为具体的每一个单元
            BrickItemInfo brick = new BrickItemInfo();    //生成的Brick数据
            bool hasDataInFile = false;
            while (!streamReader.EndOfStream)
            {
                //读取一行（Block）
                lineData = streamReader.ReadLine();
                //拆分出单元
                unitsStr = lineData.Split(':');
                int unitsCount = unitsStr.Length;

                //遍历块中获得的所有单元
                for (int i = 1; i < unitsCount; i++)                                       //i=1为初值，跳过第一个"："所生成的空格
                {
                    //尝试建立BrickItemInfo，如果失败则到下一个
                    if (brick.FromSavedString(unitsStr[i]) == false)
                    {
                        continue;
                    }

                    //Push进内存
                    PushBrickData(brick);

                    //标记从文件中读取到了数据
                    hasDataInFile = true;
                }
            }

            //关闭文件流
            streamReader.Close();
            streamReader.Dispose();
            return hasDataInFile;

        }

        /// <summary>
        /// 获取所有地图的存储路径
        /// </summary>
        /// <returns></returns>
        private string GetMapSavePath()
        {
            string savePath =
                //目录生成：
#if UNITY_STANDALONE || UNITY_EDITOR
            Application.dataPath + "/../MapData/";
#elif MOBILE_INPUT
            Application.persistentDataPath + "/MapData/";
#else
                AppDomain.CurrentDomain.BaseDirectory + "/MapData/";
#endif

            if (!Directory.Exists(savePath))
            {
                Debug.Log("NO exist. create:");
                Directory.CreateDirectory(savePath);
            }

            return savePath;
        }

        /// <summary>
        /// 获得当前游戏地图存储目录: (含地图名，当目录不存在时自动创建该目录)
        /// </summary>
        private string GetCurrMapDataPath()
        {
            string filePath = GetMapSavePath();

            if (m_currMapNamePainting != null)
            {
                filePath += m_currMapNamePainting + "/";
            }

            if (!Directory.Exists(filePath))
            {
                Debug.Log("NO exist. create:");
                Directory.CreateDirectory(filePath);
            }

            return filePath;
        }


        /// <summary>
        /// 获得地图中图块的文件名字（带后缀名）
        /// </summary>
        private string GetMapBlockNameAt(int i_area, int j_area)
        {
            return i_area + "-" + j_area + ".map";
        }

        private string GetMapSettingName()
        {
            return "Setting.ini";
        }

        #endregion

    }


#if !UNITY_EDITOR
    public struct Vector3
    {
        public static Vector3 zero = new Vector3() { x = 0, y = 0, z = 0 };
        public float x, y, z;
    }
#endif
}
